const auth=firebase.auth(),dbb=firebase.firestore(); dbb.enablePersistence().catch(()=>{}); let currentUser=null,cloudMode=false,authReady=false,ignoreSnap=false,unsubSnap=null,menuOpen=false,showAddForm=null; function signIn(){auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()).catch(e=>alert("Sign in failed: "+e.message));} function signOut2(){if(unsubSnap)unsubSnap();auth.signOut();currentUser=null;cloudMode=false;S=dflt();R();} auth.onAuthStateChanged(function(u){ authReady=true; if(u){currentUser=u;cloudMode=true; unsubSnap=dbb.collection("users").doc(u.uid).onSnapshot(function(doc){ if(ignoreSnap){ignoreSnap=false;return;} if(doc.exists&&doc.data().appData){try{S=JSON.parse(doc.data().appData);if(!S.months)S.months={};svL(S);const ae=document.activeElement;if(!ae||ae.tagName==="BODY"||ae.tagName==="BUTTON")R();}catch(e){}} else{S=ldL()||dflt();ignoreSnap=true;svCloud();R();} },function(){S=ldL()||dflt();R();}); }else{currentUser=null;R();} }); const LK="kpr-fin7"; function svL(d){try{localStorage.setItem(LK,JSON.stringify(d))}catch(e){}} function ldL(){try{return JSON.parse(localStorage.getItem(LK))}catch{return null}} let svT=null; function sv(){svL(S);if(cloudMode&¤tUser){clearTimeout(svT);svT=setTimeout(svCloud,1000);}} function svCloud(){if(!currentUser)return;ignoreSnap=true;dbb.collection("users").doc(currentUser.uid).set({appData:JSON.stringify(S),email:currentUser.email,updatedAt:firebase.firestore.FieldValue.serverTimestamp()},{merge:true}).catch(()=>{ignoreSnap=false;});} const CTRY=[{code:"us",name:"United States",flag:"๐Ÿ‡บ๐Ÿ‡ธ",cur:"USD",sym:"$"},{code:"in",name:"India",flag:"๐Ÿ‡ฎ๐Ÿ‡ณ",cur:"INR",sym:"โ‚น"},{code:"uk",name:"United Kingdom",flag:"๐Ÿ‡ฌ๐Ÿ‡ง",cur:"GBP",sym:"ยฃ"},{code:"ca",name:"Canada",flag:"๐Ÿ‡จ๐Ÿ‡ฆ",cur:"CAD",sym:"C$"},{code:"au",name:"Australia",flag:"๐Ÿ‡ฆ๐Ÿ‡บ",cur:"AUD",sym:"A$"},{code:"sg",name:"Singapore",flag:"๐Ÿ‡ธ๐Ÿ‡ฌ",cur:"SGD",sym:"S$"},{code:"ae",name:"UAE",flag:"๐Ÿ‡ฆ๐Ÿ‡ช",cur:"AED",sym:"ุฏ.ุฅ"},{code:"de",name:"Germany",flag:"๐Ÿ‡ฉ๐Ÿ‡ช",cur:"EUR",sym:"โ‚ฌ"},{code:"fr",name:"France",flag:"๐Ÿ‡ซ๐Ÿ‡ท",cur:"EUR",sym:"โ‚ฌ"},{code:"jp",name:"Japan",flag:"๐Ÿ‡ฏ๐Ÿ‡ต",cur:"JPY",sym:"ยฅ"}]; const ALL_CUR=["USD","INR","GBP","CAD","AUD","SGD","AED","EUR","JPY","CNY","KRW","THB","MYR","PHP","IDR","BRL","MXN","ZAR","TRY","CHF","SEK","NOK","NZD","HKD","PKR","BDT","LKR","SAR"]; const CC={us:["Chase Sapphire Preferred","Chase Sapphire Reserve","Chase Freedom Unlimited","Amex Gold Card","Amex Platinum","Capital One Venture","Citi Double Cash","Discover it Cash Back","Apple Card","Wells Fargo Active Cash","Zolve Credit Card"],in:["HDFC Regalia","HDFC Millennia","HDFC Infinia","SBI SimplyCLICK","SBI Prime","ICICI Amazon Pay","ICICI Coral","Axis Flipkart","Axis ACE","RBL Platinum Maxima","Kotak 811","OneCard"],uk:["Amex Platinum Cashback","Barclaycard Avios Plus","Halifax Clarity","HSBC Premier","Monzo Flex"],ca:["TD Cash Back Visa","RBC Avion","Scotiabank Gold Amex","Amex Cobalt"],au:["CommBank Awards","ANZ Rewards Black","Westpac Altitude Black"],sg:["DBS Altitude","OCBC 365","UOB One Card"],ae:["Emirates NBD Skywards","ADCB SimplyLife","FAB Cashback"],de:["Amex Gold Germany","DKB Visa","N26 You"],fr:["BNP Paribas Visa Premier","Revolut Premium"],jp:["JCB Gold","Rakuten Card","MUFG Card Gold"]}; const LN={us:["Wells Fargo","Chase Auto","Capital One Auto","Rocket Mortgage","Sallie Mae","SoFi","Affirm"],in:["HDFC Bank","ICICI Bank","SBI","Bajaj Finserv","Muthoot Finance","CRED Cash","Groww Loans"],uk:["Lloyds Bank","Barclays","Halifax","Student Loans Company"],ca:["RBC","TD Canada Trust","Scotiabank","NSLSC"],au:["CommBank","ANZ","Westpac","HECS-HELP"],sg:["DBS","OCBC","UOB","HDB"],ae:["Emirates NBD","ADCB","FAB"],de:["Deutsche Bank","DKB","Sparkasse"],fr:["BNP Paribas","Crรฉdit Agricole"],jp:["MUFG Bank","SMBC","JASSO"]}; const BK={us:["Chase","Bank of America","Wells Fargo","Citibank","Capital One","Ally Bank","EarnIn","Chime","SoFi"],in:["HDFC Bank","ICICI Bank","SBI","Axis Bank","Kotak Mahindra","IDFC FIRST"],uk:["Lloyds","Barclays","HSBC UK","Monzo","Revolut"],ca:["RBC","TD Canada Trust","Scotiabank","BMO"],au:["CommBank","ANZ","Westpac","NAB"],sg:["DBS","OCBC","UOB"],ae:["Emirates NBD","ADCB","FAB"],de:["Deutsche Bank","DKB","N26"],fr:["BNP Paribas","Boursorama"],jp:["MUFG Bank","SMBC","Rakuten Bank"]}; const IT=["SIP","Stocks","Gold","Crypto","Mutual Funds","Bonds","Real Estate","Other"]; const SO=["Pending","Paid","Overdue","Partial"]; const ECAT=["Housing","Utilities","Insurance","Transport","Food","Health","Entertainment","Shopping","Education","Subscriptions","EMI","Other"]; const uid=()=>Date.now().toString(36)+Math.random().toString(36).slice(2,6); const esc=s=>(s||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'"); const FBR={USD:1,INR:83.5,GBP:0.79,CAD:1.36,AUD:1.53,SGD:1.34,AED:3.67,EUR:0.92,JPY:154.5,CNY:7.24,KRW:1340,THB:35.5,MYR:4.47,PHP:56.5,IDR:15800,BRL:5.05,MXN:17.2,ZAR:18.6,TRY:32.5,CHF:0.88,SEK:10.5,NOK:10.8,NZD:1.65,HKD:7.82,PKR:278,BDT:110,LKR:320,SAR:3.75}; let lR=null; async function fetchR(){try{const r=await fetch("https://api.exchangerate-api.com/v4/latest/USD");if(r.ok){lR=(await r.json()).rates;R();}}catch(e){try{const r2=await fetch("https://open.er-api.com/v6/latest/USD");if(r2.ok){lR=(await r2.json()).rates;R();}}catch(e2){}}} function gR(f,t){if(f===t)return 1;const r=lR||FBR;return(r[t]||1)/(r[f]||1);} function cvt(a,f,t){if(S.curMode==="single")return parseFloat(a)||0;return(parseFloat(a)||0)*gR(f,t);} function gIC(cc){const c=CTRY.find(x=>x.code===cc);return c?c.cur:"USD";} function gCS(c){const x=CTRY.find(z=>z.cur===c);return x?x.sym:(c||"$");} fetchR(); function cMK(){const d=new Date();return d.getFullYear()+"-"+String(d.getMonth()+1).padStart(2,"0");} function gMM(mk){const c=cMK();if(mk===c)return"current";return mki.name).filter(Boolean);} function sCvt(arr,vk,ck){return arr.reduce((t,i)=>t+cvt(i[vk],i[ck]||i.currency||"USD",S.ac),0);} function sOCvt(obj,vk){return Object.values(obj).reduce((t,i)=>t+cvt(i[vk]||0,i.currency||gIC(i.country),S.ac),0);} function canP(){if(S.ss===1)return S.ut==="personal"||(S.ut==="business"&&S.bn.trim());if(S.ss===2)return S.cb.every(b=>b.c&&b.n>0&&b.it.length===b.n);if(S.ss===3)return S.lb.every(b=>b.c&&b.n>0&&b.it.length===b.n);if(S.ss===4)return S.bb.every(b=>b.c&&b.n>0&&b.it.length===b.n);return true;} function goBack(){if(S.ss>1){S.ss--;openDD=null;R();}} function goNext(){ if(S.ss===7){ // Init first month data const mk=cMK();if(!S.months)S.months={}; const md={cd:{},ld2:{},bd:{},vd:{},me:[],ye:[],is:[],gl:[]}; S.cb.forEach(b=>{const cur=gIC(b.c);b.it.forEach(i=>{md.cd[i]={currency:cur,totalLimit:"",used:"",dueDate:"",thisMonthPayment:"",source:"",status:"Pending",notes:"",country:b.c};});}); S.lb.forEach(b=>{const cur=gIC(b.c);b.it.forEach(i=>{md.ld2[i]={currency:cur,totalLoan:"",balance:"",dueDate:"",thisMonthPayment:"",source:"",status:"Pending",notes:"",country:b.c};});}); S.bb.forEach(b=>b.it.forEach(i=>{md.bd[i]={balance:"",country:b.c,currency:gIC(b.c)};})); S.iv.forEach(v=>{if(v.name)md.vd[v.name]={amount:v.amount,type:v.type,currency:v.currency,source:"",status:"Pending"};}); S.months[mk]=md; S.ac=CTRY.find(c=>c.code===S.cb[0]?.c)?.cur||"USD";S.sd=true;S.selMonth=mk; }else S.ss++; openDD=null;R(); } function cSel(){ if(S.curMode==="single")return""; const rate=gR("USD",S.ac);const rt=S.ac==="USD"?"Base":`1 USD = ${rate.toFixed(2)} ${S.ac}`; return`
${rt}${lR?" โœ“":""}
`; } function mSel(){ const mk=S.selMonth||cMK();const mode=gMM(mk); return`
${{current:"Current",history:"History",budget:"Budget"}[mode]}
`; } function cDel(){return confirm("Are you sure you want to delete this?");} // Copy month data function copyMonth(from,to){ if(!S.months[from]){alert("Source month has no data");return;} if(S.months[to]&&!confirm("Destination month already has data. Overwrite?"))return; S.months[to]=JSON.parse(JSON.stringify(S.months[from])); sv();alert("Data copied from "+gML(from)+" to "+gML(to));R(); } // โ”€โ”€ EVENTS โ”€โ”€ document.addEventListener("click",function(e){ if(menuOpen&&!e.target.closest(".hmenu")){menuOpen=false;R();return;} const t=e.target.closest("[data-a]");if(!t)return;e.stopPropagation(); const a=t.dataset.a,p=t.dataset; if(a==="none")return; const md=mD(); switch(a){ case"login":signIn();break; case"logout":signOut2();break; case"gohome":S.at="home";S.hp=null;menuOpen=false;showAddForm=null;R();break; case"menu":menuOpen=!menuOpen;R();break; case"ut":S.ut=p.v;R();break; case"open":openDD=p.id;R();break; case"close":openDD=null;R();break; case"selc":{const b=S[p.k].find(x=>x.id===p.bid);if(b&&b.c!==p.v){b.c=p.v;b.n=0;b.it=[];b.cu=[];}openDD=null;R();break;} case"inc":{const b=S[p.k].find(x=>x.id===p.bid);if(b)b.n=Math.min(b.n+1,30);R();break;} case"dec":{const b=S[p.k].find(x=>x.id===p.bid);if(b&&b.n>0){b.n--;if(b.it.length>b.n)b.it=b.it.slice(0,b.n);}R();break;} case"tog":{const b=S[p.k].find(x=>x.id===p.bid);if(b){const i=b.it.indexOf(p.v);if(i>-1)b.it.splice(i,1);else if(b.it.length=b.n)openDD=null;}R();break;} case"rmi":{const b=S[p.k].find(x=>x.id===p.bid);if(b){b.it=b.it.filter(x=>x!==p.v);b.cu=b.cu.filter(x=>x!==p.v);}R();break;} case"cust":{const nm=prompt("Enter custom name:");if(nm&&nm.trim()){const b=S[p.k].find(x=>x.id===p.bid);if(b){if(!b.cu.includes(nm.trim()))b.cu.push(nm.trim());if(b.it.length=b.n)openDD=null;}}R();break;} case"addb":S[p.k].push({id:uid(),c:null,n:0,it:[],cu:[]});openDD=null;R();break; case"rmb":if(cDel()){S[p.k]=S[p.k].filter(x=>x.id!==p.bid);if(!S[p.k].length)S[p.k]=[{id:uid(),c:null,n:0,it:[],cu:[]}];openDD=null;R();}break; case"next":goNext();break;case"back":goBack();break; case"skip":if(S.ss<=1)break;if(S.ss===7)goNext();else{S.ss++;openDD=null;R();}break; case"tab":S.at=p.v;S.hp=null;showAddForm=null;R();break; case"sub":S.hp=p.v;showAddForm=null;R();break; case"subback":S.hp=null;showAddForm=null;R();break; case"theme":S.th=S.th==="dark"?"light":"dark";menuOpen=false;sv();R();break; case"settings":S.hp="settings";S.at="home";menuOpen=false;R();break; case"about":S.hp="about";S.at="home";menuOpen=false;R();break; case"cursettings":S.hp="cursettings";S.at="home";menuOpen=false;R();break; case"copydata":S.hp="copydata";S.at="home";menuOpen=false;R();break; case"showaf":showAddForm=p.t;R();break; case"hideaf":showAddForm=null;R();break; // Quick add from settings - navigate to tab and show form case"qacc":S.at="cc";S.hp=null;showAddForm="cc";menuOpen=false;R();break; case"qaln":S.at="loans";S.hp=null;showAddForm="ln";menuOpen=false;R();break; case"qabk":S.at="banks";S.hp=null;showAddForm="bk";menuOpen=false;R();break; case"qaiv":S.at="investments";S.hp=null;showAddForm="iv";menuOpen=false;R();break; case"qame":S.at="home";S.hp="monthly";showAddForm=null;menuOpen=false;R();break; case"qaye":S.at="home";S.hp="yearly";showAddForm=null;menuOpen=false;R();break; case"qais":S.at="home";S.hp="managePay";showAddForm=null;menuOpen=false;R();break; case"qagl":S.at="home";S.hp="gl";showAddForm=null;menuOpen=false;R();break; // Save inline forms case"savecc":{const f=document.getElementById("af");if(!f)break;const nm=f.querySelector("[name=name]")?.value?.trim();if(!nm){alert("Name required");break;} md.cd[nm]={currency:f.querySelector("[name=currency]")?.value||"USD",totalLimit:f.querySelector("[name=totalLimit]")?.value||"",used:f.querySelector("[name=used]")?.value||"",dueDate:f.querySelector("[name=dueDate]")?.value||"",thisMonthPayment:"",source:"",status:"Pending",notes:f.querySelector("[name=notes]")?.value||"",country:"us"}; showAddForm=null;sv();R();break;} case"saveln":{const f=document.getElementById("af");if(!f)break;const nm=f.querySelector("[name=name]")?.value?.trim();if(!nm){alert("Name required");break;} md.ld2[nm]={currency:f.querySelector("[name=currency]")?.value||"USD",totalLoan:f.querySelector("[name=totalLoan]")?.value||"",balance:f.querySelector("[name=balance]")?.value||"",dueDate:f.querySelector("[name=dueDate]")?.value||"",thisMonthPayment:"",source:"",status:"Pending",notes:f.querySelector("[name=notes]")?.value||"",country:"us"}; showAddForm=null;sv();R();break;} case"savebk":{const f=document.getElementById("af");if(!f)break;const nm=f.querySelector("[name=name]")?.value?.trim();if(!nm){alert("Name required");break;} md.bd[nm]={balance:f.querySelector("[name=balance]")?.value||"",currency:f.querySelector("[name=currency]")?.value||"USD",country:"us"}; showAddForm=null;sv();R();break;} case"saveiv":{const f=document.getElementById("af");if(!f)break;const nm=f.querySelector("[name=name]")?.value?.trim();if(!nm){alert("Name required");break;} md.vd[nm]={amount:f.querySelector("[name=amount]")?.value||"",type:f.querySelector("[name=type]")?.value||"Stocks",currency:f.querySelector("[name=currency]")?.value||"USD",source:"",status:"Pending"}; showAddForm=null;sv();R();break;} case"rmcc":if(cDel()){delete md.cd[p.v];sv();R();}break; case"rmln":if(cDel()){delete md.ld2[p.v];sv();R();}break; case"rmbk":if(cDel()){delete md.bd[p.v];sv();R();}break; case"rmiv2":if(cDel()){delete md.vd[p.v];sv();R();}break; case"adde":{md[p.k].push({id:uid(),name:"",amount:"",currency:S.ac,category:"Other",dueDate:"",payDate:"",paySource:"",status:"Pending"});sv();R();break;} case"rme":if(cDel()){md[p.k].splice(+p.i,1);sv();R();}break; case"addis":md.is.push({id:uid(),name:"",type:"Salary",amount:"",tax:"",afterTax:"",currency:S.ac});sv();R();break; case"rmis":if(cDel()){md.is.splice(+p.i,1);sv();R();}break; case"addgl":md.gl.push({id:uid(),name:"",debits:[{acc:"",amt:""}],credits:[{acc:"",amt:""}],date:"",currency:S.ac});sv();R();break; case"rmgl":if(cDel()){md.gl.splice(+p.i,1);sv();R();}break; case"addi":{S.iv.push({id:uid(),name:"",type:"Stocks",amount:"",currency:S.ac});R();break;} case"rmiv":if(cDel()){S.iv.splice(+p.i,1);R();}break; case"refresh":fetchR();menuOpen=false;break; case"docopy":{const from=document.getElementById("copy-from")?.value;const to=document.getElementById("copy-to")?.value;if(from&&to&&from!==to)copyMonth(from,to);break;} case"setcurmode":S.curMode=p.v;sv();R();break; case"setdefcur":S.ac=document.getElementById("defcur-sel")?.value||S.ac;sv();R();break; } }); document.addEventListener("click",function(e){if(openDD&&!e.target.closest(".dw")){openDD=null;R();}}); document.addEventListener("input",function(e){ if(e.target.dataset.sf){const q=e.target.value.toLowerCase();const l=e.target.closest(".dp").querySelector(".dl");if(l)Array.from(l.children).forEach(el=>{el.style.display=el.textContent.toLowerCase().includes(q)?"":"none";});} if(e.target.dataset.ed){const d=e.target.dataset;const md=mD(); if(d.md&&d.idx!==undefined&&d.key){if(md[d.md]&&md[d.md][+d.idx])md[d.md][+d.idx][d.key]=e.target.value;} else if(d.mobj&&d.sub&&d.key){if(md[d.mobj]&&md[d.mobj][d.sub])md[d.mobj][d.sub][d.key]=e.target.value;} else if(d.arr&&d.idx!==undefined&&d.key){if(S[d.arr]&&S[d.arr][+d.idx])S[d.arr][+d.idx][d.key]=e.target.value;} else if(d.field){S[d.field]=e.target.value;} if(d.md==="is"&&(d.key==="amount"||d.key==="tax")){const inc=md.is[+d.idx];if(inc){inc.afterTax=((parseFloat(inc.amount)||0)-(parseFloat(inc.tax)||0)).toFixed(2);const el=document.getElementById("at-"+d.idx);if(el)el.textContent=gCS(inc.currency)+inc.afterTax;}} sv();} }); document.addEventListener("change",function(e){ if(e.target.dataset.ed){const d=e.target.dataset;const md=mD(); if(d.md&&d.idx!==undefined&&d.key){if(md[d.md]&&md[d.md][+d.idx])md[d.md][+d.idx][d.key]=e.target.value;} else if(d.mobj&&d.sub&&d.key){if(md[d.mobj]&&md[d.mobj][d.sub])md[d.mobj][d.sub][d.key]=e.target.value;} else if(d.arr&&d.idx!==undefined&&d.key){if(S[d.arr]&&S[d.arr][+d.idx])S[d.arr][+d.idx][d.key]=e.target.value;} if(d.md==="is"&&d.key==="type"){const inc=md.is[+d.idx];if(inc){inc.afterTax=inc.type==="Salary"?((parseFloat(inc.amount)||0)-(parseFloat(inc.tax)||0)).toFixed(2):(inc.amount||"");}} sv();if(d.rr)R();} }); // โ”€โ”€ RENDER โ”€โ”€ let rg=false; function R(){ if(rg)return;rg=true;svL(S); const app=document.getElementById("app");app.className="app"+(S.th==="light"?" light":""); document.body.className=S.th==="light"?"light":"";document.documentElement.className=S.th==="light"?"light":""; if(!authReady){app.innerHTML=`
Loading...
`;rg=false;return;} if(!currentUser){app.innerHTML=``;rg=false;return;} let h=""; if(!S.sd){h=rSetup();} else{ // Top bar h+=`
`; if(menuOpen){h+=`
`; if(currentUser){h+=`
${currentUser.photoURL?``:""}
${currentUser.displayName||"User"}
`;} h+=`
๐Ÿ’ฑ Currency settings
`; h+=`
๐Ÿ“‹ Copy month data
`; h+=`
โš™๏ธ Settings
`; h+=`
โ„น๏ธ About
`; h+=`
๐Ÿšช Logout
`;} h+=`
`; h+=`
`; if(S.at==="home")h+=rHome();else h+=rAcct(S.at); h+=`
`; // Bottom nav - modern icons, home is center circle icon-only h+=`
`; [{k:"cc",l:"Cards",i:"๐Ÿ’ณ"},{k:"loans",l:"Loans",i:"๐Ÿฆ"},{k:"home",l:"",i:"๐Ÿ "},{k:"banks",l:"Banks",i:"๐Ÿง"},{k:"investments",l:"Invest",i:"๐Ÿ“ˆ"}].forEach(t=>{ const act=S.at===t.k;const isH=t.k==="home"; h+=``; }); h+=`
`; } app.innerHTML=h;rg=false; } // โ”€โ”€ SETUP โ”€โ”€ function rSetup(){ const ST=["Use Type","Cards","Loans","Banks","Monthly","Yearly","Investments"]; let h=`
`; // Logout top right during setup h+=`
`; h+=`
`; ST.forEach((nm,i)=>{const n=i+1,cls=S.ss>n?"d":S.ss===n?"a":"";h+=`${S.ss>n?"โœ“":n}${nm}${iโ€บ':""}`;}); h+=`
`; if(S.ss===1){h+=`

Who are you setting this up for?

Pick the option that fits.

`; [{k:"personal",ic:"๐Ÿ‘ค",t:"Personal use",d:"Track your own cards, loans, expenses & investments."},{k:"business",ic:"๐Ÿ’ผ",t:"Business",d:"Track business cards, working capital & operating costs."}].forEach(o=>{h+=`
${S.ut===o.k?"โœ“":""}
${o.ic}

${o.t}

${o.d}

`;}); h+=`
`;if(S.ut==="business")h+=`
`; }else if(S.ss>=2&&S.ss<=4){ const cfg=[,,{k:"cb",cat:CC,lb:"credit cards",cl:"Add custom card",ti:"Add your credit cards"},{k:"lb",cat:LN,lb:"loans",cl:"Add custom lender",ti:"Add your loans"},{k:"bb",cat:BK,lb:"bank accounts",cl:"Add custom bank",ti:"Add your bank accounts"}][S.ss]; h+=`

${cfg.ti}

Pick country, count, and select.

`; S[cfg.k].forEach((b,idx)=>{const co=b.c?CTRY.find(x=>x.code===b.c):null;const opts=b.c?[...(cfg.cat[b.c]||[]),...b.cu]:[]; h+=`
Country ${idx+1}`;if(S[cfg.k].length>1)h+=``;h+=`
`; const cid=cfg.k+"-c-"+b.id;h+=`
`; if(openDD===cid){h+=`
`;CTRY.forEach(c=>{h+=`
${c.flag} ${c.name}${b.c===c.code?" โœ“":""}
`;});h+=`
`;}h+=`
`; h+=`
${b.n}
${!b.c?"Pick a country first":b.n===0?"Use + to set count":b.it.length+" of "+b.n+" selected"}
`; if(b.c&&b.n>0){const mid=cfg.k+"-i-"+b.id,lr=b.it.length>=b.n; h+=`
`; if(openDD===mid){h+=`
+ ${cfg.cl}
`; opts.forEach(o=>{const sel=b.it.includes(o),dis=!sel&&lr;h+=`
${esc(o)}${sel?" โœ“":""}
`;});h+=`
`;}h+=`
`; if(b.it.length===b.n)h+=`
โœ“ All ${b.n} selected
`; if(b.it.length>0){h+=`
`;b.it.forEach(i=>{h+=`${esc(i)}`;});h+=`
`;} }h+=`
`;}); h+=``; }else if(S.ss===5||S.ss===6){const key=S.ss===5?"me":"ye",title=S.ss===5?"Monthly expenses":"Yearly expenses",md=mD(); if(!md[key])md[key]=[]; h+=`

${title}

Add your costs with category.

`; h+=`
NameAmountCurCategory${key==="ye"?"Pay date":""}
`; md[key].forEach((e,i)=>{h+=`
${key==="ye"?``:""}
`;}); h+=`
`; }else if(S.ss===7){ h+=`

Investments

Add platforms you track.

NameTypeAmountCur
`; S.iv.forEach((v,i)=>{h+=`
`;}); h+=`
`; } const cp=canP();const canSkip=S.ss>1; h+=`
${canSkip?``:""}
`;return h; } // โ”€โ”€ HOME โ”€โ”€ function rHome(){ const sym=gS(),md=mD(),ps=gPS(),ro=isRO(),mode=gMM(S.selMonth||cMK()); if(S.hp==="monthly")return rExpPg("me","Monthly Expenses",sym,ps,ro,md); if(S.hp==="yearly")return rExpPg("ye","Yearly Expenses",sym,ps,ro,md); if(S.hp==="managePay")return rMP(sym,ro,md); if(S.hp==="gl")return rGL(sym,ro,md); if(S.hp==="settings")return rSettings(); if(S.hp==="about")return rAbout(); if(S.hp==="cursettings")return rCurSettings(); if(S.hp==="copydata")return rCopyData(); const tInc=sCvt(md.is||[],"afterTax","currency")||sCvt(md.is||[],"amount","currency"); const tTax=sCvt(md.is||[],"tax","currency"); const ccT=sOCvt(md.cd||{},"thisMonthPayment");const lnT=sOCvt(md.ld2||{},"thisMonthPayment"); const moT=sCvt(md.me||[],"amount","currency"); const mk=S.selMonth||cMK();const[,mm]=mk.split("-"); const yeF=(md.ye||[]).filter(e=>e.payDate&&e.payDate.split("-")[1]===mm); const yrT=sCvt(yeF,"amount","currency"); const ivT=sCvt(Object.values(md.vd||{}),"amount","currency"); const tSp=ccT+lnT+moT+yrT+ivT;const net=tInc-tSp; const assets=sOCvt(md.bd||{},"balance")+ivT; const ccBal=Object.values(md.cd||{}).reduce((t,c)=>t+cvt(c.used||0,c.currency||"USD",S.ac),0); const lnBal=Object.values(md.ld2||{}).reduce((t,l)=>t+cvt(l.balance||0,l.currency||"USD",S.ac),0); const nw=assets-ccBal-lnBal; let h=``; h+=`
${mSel()}${cSel()}
`; if(ro)h+=`
๐Ÿ“‹ Viewing history โ€” read-only
`; if(mode==="budget")h+=`
๐Ÿ“Š Budget mode
`; h+=`
`; [{l:"๐Ÿ“… Monthly",p:"monthly"},{l:"๐Ÿ“† Yearly",p:"yearly"},{l:"๐Ÿ’ผ Income",p:"managePay"},{l:"๐Ÿ“’ GL",p:"gl"}].forEach(b=>{h+=``;}); h+=`
`; h+=`
๐Ÿ’ฐ Net Worth
${sym}${nw.toFixed(2)}
`; h+=`
`; h+=`
๐Ÿ“Š This Month
`; h+=`
`; [{l:"๐Ÿ’ต Income",v:tInc,c:"var(--ok)"},{l:"๐Ÿ›๏ธ Taxes",v:tTax,c:"var(--wrn)"},{l:"๐Ÿ’ธ Spent",v:tSp,c:"var(--err)"},{l:"โœจ Remaining",v:net,c:net<0?"var(--err)":"var(--accent)"}].forEach((r,i)=>{const br=i%2===0?"border-right:1px solid var(--bd);":"";const bb=i<2?"border-bottom:1px solid var(--bd);":"";h+=`
${r.l}
${sym}${r.v.toFixed(2)}
`;}); h+=`
Breakdown
`; [{l:"CC & Loans",v:ccT+lnT,c:"var(--err)"},{l:"Monthly & Yearly",v:moT+yrT,c:"var(--wrn)"},{l:"Investments",v:ivT,c:"var(--ok)"}].forEach(r=>{h+=`
${r.l}${sym}${r.v.toFixed(2)}
`;}); h+=`
`; return h; } function rSettings(){ let h=`

Settings

`; h+=`

Quick add

`; [{a:"qacc",l:"+ Add credit card"},{a:"qaln",l:"+ Add loan"},{a:"qabk",l:"+ Add bank account"},{a:"qaiv",l:"+ Add investment"},{a:"qame",l:"+ Add monthly expense"},{a:"qaye",l:"+ Add yearly expense"},{a:"qais",l:"+ Add income source"},{a:"qagl",l:"+ Add GL entry"}].forEach(b=>{h+=``;}); h+=`

Danger zone

`; return h; } function rAbout(){ return`

About

๐Ÿ’ฐ
v${APP_VERSION}
KPR Financial Manager
Multi-country finance tracker with cloud sync
Built with Firebase โ€ข Deployed on Vercel
`; } function rCurSettings(){ let h=`

Currency settings

`; h+=`
`; h+=`
`; h+=``; h+=``; h+=`

${S.curMode==="convert"?"Values are converted using live exchange rates":"All values shown as entered โ€” no conversion"}

`; return h; } function rCopyData(){ const opts=gMO(); let h=`

Copy month data

`; h+=`

Copy all data (cards, loans, banks, expenses, income, GL) from one month to another.

`; h+=`
`; h+=`
`; h+=`
`; return h; } function aF(type){ if(showAddForm!==type)return""; if(type==="cc")return`

Add credit card

`; if(type==="ln")return`

Add loan

`; if(type==="bk")return`

Add bank account

`; if(type==="iv")return`

Add investment

`; return""; } function rExpPg(key,title,sym,ps,ro,md){ const arr=md[key]||[];const total=sCvt(arr,"amount","currency"); let h=`

${title}

`; if(ro)h+=`
๐Ÿ“‹ History โ€” read-only
`; h+=`
Total${sym}${total.toFixed(2)}
`; const cats={};arr.forEach(e=>{const c=e.category||"Other";if(!cats[c])cats[c]=[];cats[c].push(e);}); h+=`
`; Object.entries(cats).forEach(([cat,items])=>{ const catT=items.reduce((t,e)=>t+cvt(e.amount,e.currency||"USD",S.ac),0); h+=`
${cat}${sym}${catT.toFixed(2)}
`; items.forEach(e=>{const i=arr.indexOf(e);const cv2=cvt(e.amount,e.currency||"USD",S.ac); h+=`
${esc(e.name)||"โ€”"}
${sym}${cv2.toFixed(0)}${ro?"":``}
`;}); h+=`
`; }); if(!Object.keys(cats).length)h+=`
No expenses yet
`; h+=`
`; if(!ro)h+=``; return h; } function rMP(sym,ro,md){ let h=`

Manage Income

`; if(ro)h+=`
๐Ÿ“‹ History โ€” read-only
`; h+=`
`; (md.is||[]).forEach((inc,i)=>{const iS=gCS(inc.currency); h+=`
Income #${i+1}${ro?"":``}
`; h+=`
`; if(inc.type==="Salary"){h+=`
${iS}${inc.afterTax||"0.00"}
`;} else{h+=`
`;} h+=`
`;}); h+=`
`; if(!ro)h+=``;return h; } function rGL(sym,ro,md){ let h=`

General Ledger

`; if(ro)h+=`
๐Ÿ“‹ History โ€” read-only
`; h+=`
`; (md.gl||[]).forEach((e,i)=>{ if(!e.debits)e.debits=[{acc:"",amt:""}];if(!e.credits)e.credits=[{acc:"",amt:""}]; const tDb=e.debits.reduce((t,d)=>t+(parseFloat(d.amt)||0),0); const tCr=e.credits.reduce((t,c)=>t+(parseFloat(c.amt)||0),0); const diff=tDb-tCr;const bal=Math.abs(diff)<0.01; h+=`
Txn #${i+1}${bal?"โœ“ Balanced":"Diff: "+gCS(e.currency||"USD")+Math.abs(diff).toFixed(2)}
${ro?"":``}
`; h+=``; h+=`
`; h+=`
DEBIT${gCS(e.currency||"USD")}${tDb.toFixed(2)}
`; e.debits.forEach((d,j)=>{h+=`
${ro?"":``}
`;}); if(!ro)h+=``; h+=`
`; h+=`
CREDIT${gCS(e.currency||"USD")}${tCr.toFixed(2)}
`; e.credits.forEach((c,j)=>{h+=`
${ro?"":``}
`;}); if(!ro)h+=``; h+=`
`; }); h+=`
`; if(!ro)h+=``; const gDb=(md.gl||[]).reduce((t,e)=>t+(e.debits||[]).reduce((s,d)=>s+cvt(d.amt,e.currency||"USD",S.ac),0),0); const gCr=(md.gl||[]).reduce((t,e)=>t+(e.credits||[]).reduce((s,c)=>s+cvt(c.amt,e.currency||"USD",S.ac),0),0); h+=`
Debits
${sym}${gDb.toFixed(2)}
Credits
${sym}${gCr.toFixed(2)}
Balance
${Math.abs(gDb-gCr)<0.01?"โœ“ Balanced":sym+Math.abs(gCr-gDb).toFixed(2)}
`; return h; } // โ”€โ”€ ACCOUNT PAGES โ”€โ”€ function rAcct(type){ const sym=gS(),ro=isRO(),ps=gPS(),md=mD(); if(type==="cc")return rCCP(sym,ro,ps,md); if(type==="loans")return rLnP(sym,ro,ps,md); if(type==="banks")return rBkP(sym,ro,md); if(type==="investments")return rIvP(sym,ro,ps,md); return""; } function rCCP(sym,ro,ps,md){ const data=md.cd||{},items=Object.keys(data); const tUsed=items.reduce((t,k)=>t+cvt(data[k].used||0,data[k].currency||"USD",S.ac),0); const tLim=items.reduce((t,k)=>t+cvt(data[k].totalLimit||0,data[k].currency||"USD",S.ac),0); let h=`

Credit Cards

${cSel()}
`; if(ro)h+=`
๐Ÿ“‹ History โ€” read-only
`; h+=`
Limit (${S.ac})
${sym}${tLim.toFixed(2)}
Used (${S.ac})
${sym}${tUsed.toFixed(2)}
`; h+=aF("cc"); h+=`
`; if(!items.length)h+=`
No cards yet
`; items.forEach(name=>{const it=data[name];const c=it.currency||"USD";const cs=gCS(c);const avail=(parseFloat(it.totalLimit)||0)-(parseFloat(it.used)||0); h+=`
${esc(name)} (${c})
${ro?"":``}
`; h+=`
${cs}${avail.toFixed(2)}
`; h+=`
`; if(it.notes||!ro)h+=`
`; h+=`
`;}); h+=`
`; if(!ro)h+=``; return h; } function rLnP(sym,ro,ps,md){ const data=md.ld2||{},items=Object.keys(data); const tBal=items.reduce((t,k)=>t+cvt(data[k].balance||0,data[k].currency||"USD",S.ac),0); let h=`

Loans

${cSel()}
`; if(ro)h+=`
๐Ÿ“‹ History โ€” read-only
`; h+=`
Outstanding (${S.ac})
${sym}${tBal.toFixed(2)}
`; h+=aF("ln"); h+=`
`; if(!items.length)h+=`
No loans yet
`; items.forEach(name=>{const it=data[name];const c=it.currency||"USD";const cs=gCS(c);const pO=(parseFloat(it.totalLoan)||0)-(parseFloat(it.balance)||0); h+=`
${esc(name)} (${c})
${ro?"":``}
`; h+=`
${cs}${pO.toFixed(2)}
`; h+=`
`; if(it.notes||!ro)h+=`
`; h+=`
`;}); h+=`
`; if(!ro)h+=``; return h; } function rBkP(sym,ro,md){ const data=md.bd||{},items=Object.keys(data); const tBal=items.reduce((t,k)=>t+cvt(data[k].balance||0,data[k].currency||gIC(data[k].country),S.ac),0); let h=`

Banks

${cSel()}
`; if(ro)h+=`
๐Ÿ“‹ History โ€” read-only
`; h+=`
Total (${S.ac})
${sym}${tBal.toFixed(2)}
`; h+=aF("bk"); h+=`
`; if(!items.length)h+=`
No accounts yet
`; items.forEach(name=>{const it=data[name];const c=it.currency||gIC(it.country); h+=`
${esc(name)} (${c})
${ro?"":``}
`; h+=`
`; if(c!==S.ac)h+=`
โ‰ˆ ${sym}${cvt(it.balance,c,S.ac).toFixed(2)} ${S.ac}
`; h+=`
`;}); h+=`
`; if(!ro)h+=``; return h; } function rIvP(sym,ro,ps,md){ const data=md.vd||{},items=Object.keys(data); const tInv=items.reduce((t,k)=>t+cvt(data[k].amount||0,data[k].currency||"USD",S.ac),0); let h=`

Investments

${cSel()}
`; if(ro)h+=`
๐Ÿ“‹ History โ€” read-only
`; h+=`
Total (${S.ac})
${sym}${tInv.toFixed(2)}
`; h+=aF("iv"); h+=`
`; if(!items.length)h+=`
No investments yet
`; items.forEach(name=>{const it=data[name];const c=it.currency||"USD"; h+=`
${esc(name)} (${c} ยท ${it.type||"Stocks"})
${ro?"":``}
`; h+=`
`; if(c!==S.ac)h+=`
โ‰ˆ ${sym}${cvt(it.amount,c,S.ac).toFixed(2)} ${S.ac}
`; h+=`
`;}); h+=`
`; if(!ro)h+=``; return h; } R();